#include "WindowsApplication.h"

#include "Runtime/CGI/DynamicCGI.h"
#include "Runtime/Logic/EngineLoop.h"
#include "Runtime/Rendering/RendererInterface.h"

namespace Alice{
    WindowsApplication*sWindowApplication=nullptr;
    WindowsApplication*WindowsApplication::InitializeWindowsApplication(void* inParam){
        if (sWindowApplication != nullptr) {
            return sWindowApplication;
        }
		OleInitialize(NULL);
		CoInitializeEx(NULL, 0);
		WindowsApplication* windowsApplication = Alice::WindowsApplication::GetWindowsApplication();
		WNDCLASSEX wndClassEx = { 0 };
		wndClassEx.cbSize = sizeof(WNDCLASSEX);
		wndClassEx.cbClsExtra = 0;
		wndClassEx.cbWndExtra = 0;
		wndClassEx.hbrBackground = nullptr;
		wndClassEx.hCursor = LoadCursor(NULL, IDC_ARROW);
		wndClassEx.hIcon = nullptr;
		wndClassEx.hIconSm = nullptr;
		wndClassEx.hInstance = (HINSTANCE)inParam;
		wndClassEx.lpfnWndProc = AppWndProc;//function
		wndClassEx.lpszMenuName = nullptr;
		wndClassEx.lpszClassName = L"BattleFire";
		wndClassEx.style = CS_HREDRAW | CS_VREDRAW;
		//create window
		ATOM atom = RegisterClassEx(&wndClassEx);
		RECT rect = { 0 };
		rect.right = 1280;
		rect.bottom = 720;
		AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, false);
		windowsApplication->mHWND = CreateWindowEx(
			NULL, L"BattleFire", L"App Render Window", WS_OVERLAPPEDWINDOW,
			200, 200, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, (HINSTANCE)inParam, NULL);
		GetClientRect(windowsApplication->mHWND, &rect);//render region
		int canvasWidth = rect.right - rect.left;
		int canvasHeight = rect.bottom - rect.top;
        EngineInit(windowsApplication);
    	windowsApplication->mGameViewportClient=new GameViewportClient;
    	windowsApplication->mGameViewportClient->mCGIViewport=CGICreateViewport(windowsApplication->mHWND,canvasWidth,canvasHeight,false,EPixelFormat::PF_Unknown);
    	sWindowApplication=windowsApplication;
        return sWindowApplication;
    }
    WindowsApplication*WindowsApplication::GetWindowsApplication(){
		if (sWindowApplication == NULL) {
			sWindowApplication = new WindowsApplication;
		}
        return sWindowApplication;
    }
    LRESULT CALLBACK WindowsApplication::AppWndProc(HWND inHWND, uint32 inMSG, WPARAM inWParam, LPARAM inLParam){
        return sWindowApplication->ProcessMessage(inHWND,inMSG,inWParam,inLParam);
    }
    int32 WindowsApplication::ProcessMessage(HWND inHWND, uint32 inMSG, WPARAM inWParam, LPARAM inLParam){
		switch (inMSG)
		{
		case WM_CLOSE:
			mbQuit=true;//WM_QUIT
			break;
		}
        return DefWindowProc(inHWND,inMSG,inWParam,inLParam);
    }
    void WindowsApplication::Run(){
		ShowWindow(mHWND, SW_SHOW);
		UpdateWindow(mHWND);
		mbQuit = false;
		while (true) {
			{
				MSG msg;
				while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
					TranslateMessage(&msg);
					DispatchMessage(&msg);
				}
			}
			if (mbQuit) {
				break;
			}
			EngineTick();
			RHIGetViewportBackBuffer(mGameViewportClient->mCGIViewport.GetPtr());
			GetRendererModule()->BeginRenderingViewFamily();
		}
    }
}
